(ns jumpluff.utils
  (:require [cljs.core.async :as async]
            [jumpluff.state :as state])
  (:require-macros [cljs.core.async.macros :as async-macros]))

(defn dataset-names []
  (keys @state/dataset-descriptions))

(defn dataset-names-some-exact-match
  "Use `some` to look for an exact string match of `name` in `dataset-names`"
  [name]
  (some #{name} (dataset-names)))

(defn server-emoji-id [message name]
  (when (not (nil? message.channel.guild))
    (str (.-id message.channel.guild) "/" name)))

(defn promise-to-chan
  "Handle JavaScript Promises with async channels.
  Single argument arity: given a promise, return a chan that will give
  truthy on success, false on error.  Two argument arity: Given a
  `promfn` that produces a promise when given `thing`.  On an error,
  `promise-to-chan` will know how to try again with a new promise."
  ([promise]
   (let [ret (async/chan)
         success #(async/put! ret (or % true))
         failure #(do (console.error %)
                      (async/put! ret false))]
     (-> promise
        (.then success)
        (.catch failure))
     ret))
  ([promfn thing]
   (promise-to-chan promfn thing 0 1 (async/chan)))
  ([promfn thing retry-attempt retry-limit ret]
   (-> (promfn thing)
      (.then #(async/put! ret (or % true)))
      (.catch (fn [err]
                (console.error err)
                (if (and (= "EAI_AGAIN" (.-code err)) ; error codes to retry on
                         (> retry-limit retry-attempt))
                  (promise-to-chan promfn thing
                                   (inc retry-attempt) retry-limit
                                   ret)
                  (async/put! ret false)))))
   ret))

(defn vecs->maps
  "Translate a collection of vectors to a collection of maps.
  Translate `coll` according to `m` containing keys to vector indexes."
  [m coll]
  (map (fn [xs]
         (->> m
            (map (fn [[k v]]
                   {k (when (int? v)
                        (nth xs v nil))}))
            (apply merge)))
       coll))
;; (vecs->maps {:first 0 :second 1 :third 3} '(["a" "b" "c" "d"] ["a" "b" "c"]))
;; ({:first "a", :second "b", :third "d"}
;;  {:first "a", :second "b", :third nil})

(defn log [& strs]
  (println (apply str strs)))
